﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Galaktika.BI.Silverlight.Controls.PivotGrid.Data;
using Ranet.Olap.Core.DataDescription;
using Galaktika.BI.Silverlight.Controls.PivotGrid.Data.Providers;
using Galaktika.BI.Runtime.Services;
using System.ComponentModel;
using Galaktika.BI.Runtime;
using Galaktika.BI.Silverlight.Controls.PivotGrid.ClientServer;
using Galaktika.BI.Silverlight.Commands;
using System.Threading;
using Galaktika.BI.Charting;
using Galaktika.BI.Charting.PivotChart;

namespace Galaktika.BI.Silverlight.Controls.PivotGrid.Controls
{
    public delegate void PerformMemberActionEventHandler(object sender, PerformMemberActionArgs args);
    public delegate void MemberActionEventHandler(object sender, MemberActionEventArgs args);
    public delegate void CellValueChangedEventHandler(object sender, CellValueChangedEventArgs e);
    public delegate void FocusedCellChangedEventHandler(object sender, FocusedCellChangedEventArgs e);

    public partial class UpdateablePivotGridControl : UserControl, IBindableObject, IEditableObject
    {
        private bool m_IsWaiting = false;
        public bool IsWaiting
        {
            get { 
                return m_IsWaiting; 
            }
            set {

                if (m_IsWaiting != value)
                {
                    if (value)
                    {
                        this.Cursor = Cursors.Wait;
                    }
                    else
                    {
                        this.Cursor = Cursors.Arrow;    
                    }
                    m_IsWaiting = value;
                }
            }
        }

        public UpdateablePivotGridControl()
        {
            InitializeComponent();

            DataControl.Owner = this;
            DataControl.PivotGrid.ColumnsControl.DrillDownMember += new MemberActionEventHandler(ColumnsControl_DrillDownMember);
            DataControl.PivotGrid.RowsControl.DrillDownMember += new MemberActionEventHandler(RowsControl_DrillDownMember);
            DataControl.PivotGrid.CellsControl.CellValueChanged += new CellValueChangedEventHandler(CellsControl_CellValueChanged);

            RefreshButton_Image.Source = UriResources.Images.Refresh16;
            BackButton_Image.Source = UriResources.Images.Back16;
            ForwardButton_Image.Source = UriResources.Images.Forward16;

            UpdateHistoryNavigationButtons(null);
        }

        void CellsControl_CellValueChanged(object sender, CellValueChangedEventArgs e)
        {
            if (!IsWaiting)
            {
                UpdateCubeArgs olap_args = new UpdateCubeArgs();

                UpdateEntry entry = new UpdateEntry();

                IDictionary<String, MemberInfo> tuple = e.Cell.GetTuple();
                foreach (MemberInfo mi in tuple.Values)
                {
                    ShortMemberInfo tuple_mi = new ShortMemberInfo();
                    tuple_mi.HierarchyUniqueName = mi.HierarchyUniqueName;
                    tuple_mi.UniqueName = mi.UniqueName;
                    tuple_mi.LevelDepth = mi.LevelDepth;

                    entry.Tuple.Add(tuple_mi);
                }
                entry.NewValue = e.NewValue;

                if (m_CSDescr != null)
                {
                    olap_args.CubeName = m_CSDescr.CubeName;
                    olap_args.ConnectionString = m_CSDescr.ConnectionString;
                }

//                olap_args.Script = m_UpdateScript;
                olap_args.Entries = new List<UpdateEntry>();
                olap_args.Entries.Add(entry);

                IsWaiting = true;

                IBindingManager bindManager;
                this.Bindings.TryGetValue("ADataSource", out bindManager);
                if (bindManager != null)
                {
                    IUserTaskManager taskManager = (IUserTaskManager)Context.Services.GetService(typeof(IUserTaskManager));
                    if (taskManager != null)
                    {
                        InvokeSchema schema = CommandBuilder.CreateUpdateCubeSchema((string)this.Context.UserData["_$Id"], bindManager.DataManager.Name, olap_args);

                        taskManager.ProcessTaskItem(Localization.AppTask_ExecutingUpdateCubeCommand,
                            new WaitCallback(InvokeCommandBySchema),
                            schema);
                    }
                }

                //OlapWebProxy.OlapService.OlapWebServiceSoapClient service = new OlapWebProxy.OlapService.OlapWebServiceSoapClient();
                //service.InnerChannel.OperationTimeout = TimeSpan.MaxValue;
                //service.PerformUpdateCompleted += new EventHandler<OlapWebProxy.OlapService.PerformUpdateCompletedEventArgs>(service_PerformUpdateCompleted);
                //service.PerformUpdateAsync(olap_args);
            }
        }

        void UpdateCube_InvokeCommandCompleted(InvokeResultSchema res)
        {
            RunNavigationCommand(HistoryNavigationActionType.Refresh);
        }

        void UpdateButtons()
        {
            UpdateHistoryNavigationButtons(null);

            IBindingManager bindManager;
            this.Bindings.TryGetValue("ADataSource", out bindManager);
            if (bindManager != null)
            {
                IUserTaskManager taskManager = (IUserTaskManager)Context.Services.GetService(typeof(IUserTaskManager));
                if (taskManager != null)
                {
                    InvokeSchema schema = CommandBuilder.CreateToolBarInfoSchema((string)this.Context.UserData["_$Id"], bindManager.DataManager.Name);

                    taskManager.ProcessTaskItem(Localization.AppTask_DownloadingHistoryNavigation,
                        new WaitCallback(InvokeCommandBySchema),
                        schema);
                }
            }
        }

        void UpdateHistoryNavigationButtons(PivotGridToolBarInfo info)
        {
            if (info == null)
            {
                BackButton.IsEnabled = false;
                ForwardButton.IsEnabled = false;
            }
            else
            {
                if (info.HistorySize > 0)
                {
                    BackButton.IsEnabled = info.CurrentHistoryIndex > 0;
                    ForwardButton.IsEnabled = info.CurrentHistoryIndex + 1 < info.HistorySize;
                }
                else
                {
                    BackButton.IsEnabled = false;
                    ForwardButton.IsEnabled = false;
                }
            }
        }

        void ToolBarInfo_InvokeCommandCompleted(InvokeResultSchema res)
        {
            try
            {
                PivotGridToolBarInfo info = null;
                try
                {
                    info = XmlUtility.XmlStr2Obj<PivotGridToolBarInfo>(res.Content);
                }
                catch { 
                }
                UpdateHistoryNavigationButtons(info);
            }
            finally
            {
                this.Focus();
            }
        }

        void RowsControl_DrillDownMember(object sender, MemberActionEventArgs args)
        {
            if (!IsWaiting)
            {
                OnDrillDownMember(1, args);
            }
        }

        void ColumnsControl_DrillDownMember(object sender, MemberActionEventArgs args)
        {
            if (!IsWaiting)
            {
                OnDrillDownMember(0, args);
            }
        }

        private void OnDrillDownMember(int axisNum, MemberActionEventArgs args)
        {
            IsWaiting = true;
            IList<MemberInfo> full_tuple = new List<MemberInfo>();
            args.Member.CollectAncestors(full_tuple);

            List<ShortMemberInfo> list = new List<ShortMemberInfo>();
            foreach (MemberInfo mi in full_tuple)
            {
                ShortMemberInfo olap_mi = new ShortMemberInfo();
                olap_mi.UniqueName = mi.UniqueName;
                olap_mi.HierarchyUniqueName = mi.HierarchyUniqueName;
                olap_mi.LevelDepth = mi.LevelDepth;
                list.Add(olap_mi);
            }

            PerformMemberActionArgs olap_args = new PerformMemberActionArgs();
            olap_args.Action = args.Action;

            olap_args.Ascendants = list;
            olap_args.AxisIndex = axisNum;
            olap_args.Member = new ShortMemberInfo();
            olap_args.Member.UniqueName = args.Member.UniqueName;
            olap_args.Member.HierarchyUniqueName = args.Member.HierarchyUniqueName;
            olap_args.Member.LevelDepth = args.Member.LevelDepth;

            IBindingManager bindManager;
            this.Bindings.TryGetValue("ADataSource", out bindManager);
            if (bindManager != null)
            {
                IUserTaskManager taskManager = (IUserTaskManager)Context.Services.GetService(typeof(IUserTaskManager));
                if (taskManager != null)
                {
                    InvokeSchema schema = CommandBuilder.CreateDrillDownSchema((string)this.Context.UserData["_$Id"], bindManager.DataManager.Name, olap_args);

                    taskManager.ProcessTaskItem(Localization.AppTask_ExecutingDrillAction,
                        new WaitCallback(InvokeCommandBySchema),
                        schema);
                }
            }
            ////UpdateNavigationButtons();
        }

        void DrillDown_InvokeCommandCompleted(InvokeResultSchema res)
        {
            try
            {
                CellSetDescription desc = XmlUtility.XmlStr2Obj<CellSetDescription>(res.Content);
                Initialize(desc);
            }
            finally
            {
                IsWaiting = false;
                this.Focus();
                UpdateButtons();
            }
        }

        private String m_UpdateScript = String.Empty;

        public void Initialize(CellSetDescription cs_descr, String updateScript)
        {
            this.Initialize(cs_descr);
            m_UpdateScript = updateScript;
        }

        private CellSetDescription m_CSDescr = null;

        //private void Initialize(String answerFromServer)
        //{
        //    if (!String.IsNullOrEmpty(answerFromServer))
        //    {
        //        CellSetDescription cs_descr = null;
        //        try
        //        {
        //            cs_descr = XmlUtility.XmlStr2Obj<CellSetDescription>(answerFromServer);
        //        }
        //        catch
        //        {
        //            cs_descr = null;
        //        }
        //        Initialize(cs_descr);
        //    }
        //}

        public void Initialize(CellSetDescription cs_descr)
        {
            try
            {
                IsWaiting = true;

                m_CSDescr = cs_descr;

                if (cs_descr != null)
                {
                    CellSetDataProvider provider = new CellSetDataProvider(cs_descr);
                    DataControl.PivotGrid.Initialize(provider);
                }
            }
            finally {
                IsWaiting = false;
            }
        }

        public static DependencyProperty ADataSourceProperty = DependencyProperty.Register("ADataSource", typeof(object), typeof(UpdateablePivotGridControl), null);
        public object ADataSource
        {
            get
            {
                return base.GetValue(ADataSourceProperty);
            }
            set
            {
                base.SetValue(ADataSourceProperty, value);
            }
        }

        #region Действия для областей

        /// <summary>
        /// Действия для области ячеек
        /// </summary>
        public CustomList<ActionInfo> ACellsAreaContextActions
        {
            get
            {
                return DataControl.PivotGrid.CellsControl.ContextActionInfo;
            }
            set
            {
                DataControl.PivotGrid.CellsControl.ContextActionInfo = value;
            }
        }

        /// <summary>
        /// Действия для области строк
        /// </summary>
        public CustomList<ActionInfo> ARowsAreaContextActions
        {
            get
            {
                return DataControl.PivotGrid.RowsControl.ContextActionInfo;
            }
            set
            {
                DataControl.PivotGrid.RowsControl.ContextActionInfo = value;
            }
        }

        /// <summary>
        /// Действия для области столбцов
        /// </summary>
        public CustomList<ActionInfo> AColumnsAreaContextActions
        {
            get
            {
                return DataControl.PivotGrid.ColumnsControl.ContextActionInfo;
            }
            set
            {
                DataControl.PivotGrid.ColumnsControl.ContextActionInfo = value;
            }
        }
        #endregion Действия для областей

        #region IBindableObject Members

        public IBindingContext Context { get; set; }

        private IDictionary<string, IBindingManager> m_Bindings;
        public IDictionary<string, IBindingManager> Bindings
        {
            get
            {
                if (m_Bindings == null)
                {
                    m_Bindings = new SafeDictionary<string, IBindingManager>();
                }

                return m_Bindings;
            }
        }

        #endregion

        #region IEditableObject Members

        public void BeginEdit()
        {
        }

        public void CancelEdit()
        {
        }

        public void EndEdit()
        {
            CellSetDescription description = this.ADataSource as CellSetDescription;
            this.Initialize(description);
        }

        #endregion

        private void RefreshButton_Click(object sender, RoutedEventArgs e)
        {
            RunNavigationCommand(HistoryNavigationActionType.Refresh);
        }

        private void BackButton_Click(object sender, RoutedEventArgs e)
        {
            RunNavigationCommand(HistoryNavigationActionType.Back);
        }

        private void RunNavigationCommand(HistoryNavigationActionType actionType)
        {
            IBindingManager bindManager;
            this.Bindings.TryGetValue("ADataSource", out bindManager);
            if (bindManager != null)
            {
                IsWaiting = true;

                IUserTaskManager taskManager = (IUserTaskManager)Context.Services.GetService(typeof(IUserTaskManager));
                if (taskManager != null)
                {
                    InvokeSchema schema = CommandBuilder.CreateRunNavigationCommandSchema((string)this.Context.UserData["_$Id"], bindManager.DataManager.Name, actionType);

                    taskManager.ProcessTaskItem(String.Format(Localization.AppTask_ExecutingNavigationCommand, actionType.ToString()),
                        new WaitCallback(InvokeCommandBySchema),
                        schema);
                }
            }
        }

        void InvokeCommandBySchema(object state)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(InvokeCommand), state);
        }

        void InvokeCommand(object state)
        {
            InvokeSchema schema = state as InvokeSchema;
            if (schema != null)
            {
                using (SyncDataService ds = new SyncDataService())
                {
                    InvokeResultSchema res = ds.InvokeCommand(schema);

                    if (ds.Error != null)
                    {
                        LogException(ds.Error);
                        return;
                    }

                    if (schema.CommandId == Commands.CommandId.HistoryNavigationCommandId || schema.CommandId == Commands.CommandId.DrillDownCommandId)
                    {
                        this.Dispatcher.BeginInvoke(delegate { DrillDown_InvokeCommandCompleted(res); });
                        return;
                    }
                    if (schema.CommandId == Commands.CommandId.UpdateCubeCommandId)
                    {
                        this.Dispatcher.BeginInvoke(delegate { UpdateCube_InvokeCommandCompleted(res); });
                        return;
                    }
                    if (schema.CommandId == Commands.CommandId.ToolBarInfoCommandId)
                    {
                        this.Dispatcher.BeginInvoke(delegate { ToolBarInfo_InvokeCommandCompleted(res); });
                        return;
                    }
                }
            }
        }

        private bool LogException(Exception ex)
        {
            IOutputService log = (IOutputService)Context.Services.GetService(typeof(IOutputService));
            if (log != null)
            {
                log.WriteException(ex);
                return true;
            }
            return false;
        }

        private void ForwardButton_Click(object sender, RoutedEventArgs e)
        {
            RunNavigationCommand(HistoryNavigationActionType.Forward);
        }
    }
}
